﻿// -----------------------------------------------------------------------
// <copyright file="SystemColumns.cs" company="JSC Centido">
//  Copyright (c) JSC Centido. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------

namespace Centido.Core
{
    using System;
    using System.Linq;

    /// <summary>
    ///   A container of the table system columns.
    /// </summary>
    /// <remarks>Although the system columns can be found in the Columns
    /// collection, but this container provides a direct way to access a certain system column.</remarks>
    /// <example>
    ///   The following example shows how to get the system columns via the Columns property.
    /// <code>
    ///     using System;
    ///     using Centido.Core;
    /// 
    ///     class Sample
    ///     {
    ///         static void Main()
    ///         {
    ///             var domainConfig = new DomainConfiguration()
    ///             {
    ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
    ///                 DbProviderName = "MSSQLSERVER"
    ///             };
    ///         
    ///             var domain = Domain.Build(domainConfig);
    ///             
    ///             domain.DeleteAll(); 
    ///             
    ///             //Adding a new table
    ///             var table = domain.AddTable("my_table");
    /// 
    ///             //Enumerating all system columns
    ///             foreach(var systemColumn in table.Columns.Where(c => c.IsSystem))
    ///                 Console.WriteLine("System column: name = {0}, type = {1}", systemColumn.Name, systemColumn.ColumnType); 
    ///         }
    ///     }   
    /// </code>
    /// </example>
    public sealed class SystemColumns
    {
        /// <summary>
        ///   Parent table
        /// </summary>
        private readonly Table _table;
        /// <summary>
        /// The id column.
        /// </summary>
        private GuidColumn _idColumn;
        /// <summary>
        /// The owner column
        /// </summary>
        private StringColumn _ownerColumn;
        /// <summary>
        /// The CreatedBy column.
        /// </summary>
        private StringColumn _createdByColumn;
        /// <summary>
        /// The CreatedOn column.
        /// </summary>
        private DateTimeColumn _createdOnColumn;
        /// <summary>
        /// The UpdatedBy column.
        /// </summary>
        private StringColumn _updatedByColumn;
        /// <summary>
        /// The UpdatedOn column.
        /// </summary>
        private DateTimeColumn _updatedOnColumn;
        /// <summary>
        /// The DeletedBy column.
        /// </summary>
        private StringColumn _deletedByColumn;
        /// <summary>
        /// The DeletedOn column.
        /// </summary>
        private DateTimeColumn _deletedOnColumn;
        /// <summary>
        /// The IsActive column.
        /// </summary>
        private BoolColumn _isActiveColumn;
        /// <summary>
        /// The RowVersion column.
        /// </summary>
        private GuidColumn _rowVersionColumn;

        /// <summary>
        ///   Initializes a new instance of the <see cref = "Centido.Core.SystemColumns" /> class
        /// for the specified table.
        /// </summary>
        /// <param name = "table">The table that contains the system columns.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="table"/> is null.</exception>
        internal SystemColumns(Table table)
        {
            if (table == null)
                throw new ArgumentNullException("table");

            _table = table;
        }

        /// <summary>
        ///   Gets the row id system column.
        /// </summary>
        /// <remarks>The primary key of each row in any user-defined table is a unique guid id value.
        /// If the id value is not specified in an inserted row then this value is auto-generated.
        /// The value of the id column is a guid value but it is stored in the binary format for
        /// the interoperability reasons.</remarks>
        /// <example>
        ///   The following example shows that the row id value is auto-generated by the dbms if it is not specified.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll(); 
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             table.GrantAll();
        /// 
        ///             //Inserting a new row without specifying the row id
        ///             domain.DbAccess.ExecuteNonQuery(cmd =>
        ///             {
        ///                 cmd.CommandText = string.Format("insert into {0}(owner) values({1})",
        ///                     table.FullName,
        ///                     domain.DbAccess.FormatMarker("owner"));
        /// 
        ///                 cmd.Parameters.Add(domain.DbAccess.CreateParameter("owner", OdbcType.NVarChar, "new_owner"));
        ///             });
        /// 
        ///             //Reading the id of the new row
        ///             Guid autoGeneratedId = Guid.Empty;
        /// 
        ///             domain.DbAccess.ExecuteScalar(cmd =>
        ///             {
        ///                 cmd.CommandText = string.Format("select id from {0}", table.FullName);
        ///             }, result => autoGeneratedId = DbValue.GetGuid(result).Value);
        /// 
        ///             Console.WriteLine("Auto-generated id = {0}", autoGeneratedId);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public GuidColumn Id
        {
            get
            {
                return _idColumn ??
                       (_idColumn = _table.Columns.Single(c => c.Name == Db.Tables.UserTable.Col.Id) as GuidColumn);
            }
        }

        /// <summary>
        ///   Gets the row owner system column.
        /// </summary>
        /// <remarks>Each table row has a column that contains the name of the user that is considered to be its owner.
        /// If not specified otherwise the owner of an inserted row is set to the name of the current user.
        /// The owner of the row can also be changed manually.
        /// This column is the only information that determines what rows can be accessed
        /// when table permissions are set on the business unit access level.</remarks>
        /// <example>
        ///   The following example shows how to set the owner of the row and change it afterwards.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll(); 
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             table.GrantAll();
        /// 
        ///             //Inserting a new row specifying the row owner
        ///             var rowId = table.InsertRow(table.SystemColumns.Owner.Value("owner_1"));
        /// 
        ///             //Reading the owner of the new row
        ///             var insertedOwner = table.SystemColumns.Owner.Read(rowId).GetString();
        /// 
        ///             Console.WriteLine("After inserting: owner = {0}", insertedOwner);
        /// 
        ///             //Updating the owner of the row
        ///             table.SystemColumns.Owner.Update(rowId, "owner_2");
        /// 
        ///             //Reading the owner of the row
        ///             var updatedOwner = table.SystemColumns.Owner.Read(rowId).GetString();
        /// 
        ///             Console.WriteLine("After updating: owner = {0}", updatedOwner);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public StringColumn Owner
        {
            get
            {
                return _ownerColumn ??
                       (_ownerColumn =
                        _table.Columns.Single(c => c.Name == Db.Tables.UserTable.Col.Owner) as StringColumn);
            }
        }

        /// <summary>
        ///   Gets the row CreatedBy system column.
        /// </summary>
        /// <remarks>This column stores the name of the user that inserted the row.
        /// The value of this column cannot be modified.</remarks>
        /// <example>
        ///   The following example shows that the CreatedBy column is auto-generated and cannot be changed.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll(); 
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             table.GrantAll();
        ///             
        ///             //Inserting a new row
        ///             var rowId = table.InsertRow();
        /// 
        ///             //Reading the CreatedBy column
        ///             Console.WriteLine("After inserting: created by = {0}",
        ///                 table.SystemColumns.CreatedBy.Read(rowId).GetString());
        /// 
        ///             //Trying to modify the CreatedBy column
        ///             table.SystemColumns.CreatedBy.Update(rowId, DataSource.InternalTable, "new user");
        /// 
        ///             //Reading the CreatedBy column
        ///             Console.WriteLine("After updating: created by = {0}",
        ///                 table.SystemColumns.CreatedBy.Read(rowId).GetString());
        ///         }
        ///     }
        /// </code>
        /// </example>
        public StringColumn CreatedBy
        {
            get
            {
                return _createdByColumn ??
                       (_createdByColumn =
                        _table.Columns.Single(c => c.Name == Db.Tables.UserTable.Col.CreatedBy) as StringColumn);
            }
        }

        /// <summary>
        ///   Gets the row CreatedOn system column.
        /// </summary>
        /// <remarks>
        /// This column stores the date and time of the row insertion.
        /// The value of this column cannot be modified.
        /// </remarks>
        /// <example>
        ///   The following example shows that the CreatedOn column is auto-generated and cannot be changed.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll(); 
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             table.GrantAll();
        ///             
        ///             //Inserting a new row
        ///             var rowId = table.InsertRow();
        /// 
        ///             //Reading the CreatedOn column
        ///             Console.WriteLine("After inserting: created on = {0}",
        ///                 table.SystemColumns.CreatedOn.Read(rowId).GetDateTime());
        /// 
        ///             //Trying to modify the CreatedOn column
        ///             table.SystemColumns.CreatedOn.Update(rowId, DataSource.InternalTable, DateTime.Now.AddYears(2));
        /// 
        ///             //Reading the CreatedOn column
        ///             Console.WriteLine("After updating: created on = {0}",
        ///                 table.SystemColumns.CreatedOn.Read(rowId).GetDateTime());
        ///         }
        ///     }
        /// </code>
        /// </example>
        public DateTimeColumn CreatedOn
        {
            get
            {
                return _createdOnColumn ??
                       (_createdOnColumn =
                        _table.Columns.Single(c => c.Name == Db.Tables.UserTable.Col.CreatedOn) as DateTimeColumn);
            }
        }

        /// <summary>
        ///   Gets the row UpdatedBy system column.
        /// </summary>
        /// <remarks>
        /// This column stores the name of the user that updated the row last.
        /// The value of the column is modified after each update and cannot be changed manually.
        /// Initially the UpdatedBy value is set to the name of the user that inserted the row.
        /// </remarks>
        /// <example>
        ///   The following example shows that the UpdatedBy column is auto-generated and cannot be changed manually.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll(); 
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             table.GrantAll();
        ///             
        ///             //Inserting a new row
        ///             var rowId = table.InsertRow();
        /// 
        ///             //Reading the UpdatedBy column
        ///             Console.WriteLine("After inserting: updated by = {0}",
        ///                 table.SystemColumns.UpdatedBy.Read(rowId).GetString());
        /// 
        ///             //Trying to modify the UpdatedBy column
        ///             table.SystemColumns.UpdatedBy.Update(rowId, DataSource.InternalTable, "new_user");
        /// 
        ///             //Reading the UpdatedBy column
        ///             Console.WriteLine("After trying to update: updated by = {0}",
        ///                 table.SystemColumns.UpdatedBy.Read(rowId).GetString());
        /// 
        ///             //Creating a new user
        ///             var user = domain.AddUser("my_user", "P@ssw0rd");
        ///             table.GrantAll(user);
        /// 
        ///             //Logging on as a new user and updating the row
        ///             var userTable = domain.Logon("my_user", "P@ssw0rd").GetTable(table.Name);
        /// 
        ///             userTable.UpdateRow(rowId, userTable.SystemColumns.Owner.Value("new_owner"));
        /// 
        ///             //Reading the UpdatedBy column
        ///             Console.WriteLine("After updating: updated by = {0}",
        ///                 table.SystemColumns.UpdatedBy.Read(rowId).GetString());
        ///         }
        ///     }
        /// </code>
        /// </example>
        public StringColumn UpdatedBy
        {
            get
            {
                return _updatedByColumn ??
                       (_updatedByColumn =
                        _table.Columns.Single(c => c.Name == Db.Tables.UserTable.Col.UpdatedBy) as StringColumn);
            }
        }

        /// <summary>
        ///   Gets the row UpdatedOn system column.
        /// </summary>
        /// <remarks>
        /// This column stores the date and time of the last row update.
        /// The value of the column is modified after each update and cannot be changed manually.
        /// Initially the UpdatedBy value is set to the date and time of the row insertion.
        /// </remarks>
        /// <example>
        ///   The following example shows that the UpdatedBy column is auto-generated and cannot be changed manually.
        /// <code>
        ///     using System;
        ///     using System.Threading;
        ///     using Centido.Core;     
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll(); 
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             table.GrantAll();
        ///             
        ///             //Inserting a new row
        ///             var rowId = table.InsertRow();
        /// 
        ///             //Reading the UpdatedOn column
        ///             Console.WriteLine("After inserting: updated on = {0}",
        ///                 table.SystemColumns.UpdatedOn.Read(rowId).GetDateTime());
        /// 
        ///             //Trying to modify the UpdatedOn column
        ///             table.SystemColumns.UpdatedOn.Update(rowId, DataSource.InternalTable, DateTime.Now.AddYears(2));
        /// 
        ///             //Reading the UpdatedOn column
        ///             Console.WriteLine("After trying to update: updated on = {0}",
        ///                 table.SystemColumns.UpdatedOn.Read(rowId).GetDateTime());
        /// 
        ///             //Creating a new user
        ///             var user = domain.AddUser("my_user", "P@ssw0rd");
        ///             table.GrantAll(user);
        /// 
        ///             Thread.Sleep(2000);
        /// 
        ///             //Logging on as a new user and updating the row
        ///             var userTable = domain.Logon("my_user", "P@ssw0rd").GetTable(table.Name);
        /// 
        ///             userTable.UpdateRow(rowId, userTable.SystemColumns.Owner.Value("new_owner"));
        /// 
        ///             //Reading the UpdatedOn column
        ///             Console.WriteLine("After updating: updated on = {0}",
        ///                 table.SystemColumns.UpdatedOn.Read(rowId).GetDateTime());
        ///         }
        ///     }
        /// </code>
        /// </example>
        public DateTimeColumn UpdatedOn
        {
            get
            {
                return _updatedOnColumn ??
                       (_updatedOnColumn =
                        _table.Columns.Single(c => c.Name == Db.Tables.UserTable.Col.UpdatedOn) as DateTimeColumn);
            }
        }

        /// <summary>
        ///   Gets the row DeletedBy system column.
        /// </summary>
        /// <remarks>
        /// This column stores the name of the user that soft deleted the row.
        /// The value of the DeletedBy is set when the row is soft deleted
        /// and unset when the row is restored.
        /// The DeletedBy column is only visible in the internal table
        /// but not in the user view of that table.
        /// </remarks>
        /// <example>
        ///   The following example shows that the DeletedBy value is auto-generated and cannot be changed manually.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll(); 
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             table.GrantAll();
        ///             
        ///             //Inserting a new row
        ///             var rowId = table.InsertRow();
        /// 
        ///             //Reading the value of the DeletedBy column
        ///             Console.WriteLine("Before deletion: deleted by = {0}",
        ///                 table.SystemColumns.DeletedBy.Read(rowId, DataSource.InternalTable).GetString() ?? "null");
        /// 
        ///             //Trying to modify the DeletedBy value
        ///             table.SystemColumns.DeletedBy.Update(rowId, DataSource.InternalTable, "new_user");
        /// 
        ///             //Reading the value of the DeletedBy column
        ///             Console.WriteLine("After trying to update: deleted by = {0}",
        ///                 table.SystemColumns.DeletedBy.Read(rowId, DataSource.InternalTable).GetString() ?? "null");
        /// 
        ///             //Soft deleting the row
        ///             table.DeleteRow(rowId);
        /// 
        ///             //Reading the value of the DeletedBy column
        ///             Console.WriteLine("After soft deleting: deleted by = {0}",
        ///                 table.SystemColumns.DeletedBy.Read(rowId, DataSource.InternalTable).GetString() ?? "null");
        /// 
        ///             //Restoring the row
        ///             table.RestoreRow(rowId);
        /// 
        ///             //Reading the value of the DeletedBy column
        ///             Console.WriteLine("After restoring: deleted by = {0}",
        ///                 table.SystemColumns.DeletedBy.Read(rowId, DataSource.InternalTable).GetString() ?? "null");
        ///         }
        ///     }
        /// </code>
        /// </example>
        public StringColumn DeletedBy
        {
            get
            {
                return _deletedByColumn ??
                       (_deletedByColumn =
                        _table.Columns.Single(c => c.Name == Db.Tables.UserTable.Col.DeletedBy) as StringColumn);
            }
        }

        /// <summary>
        ///   Gets the row DeletedOn system column.
        /// </summary>
        /// <remarks>
        ///   This column stores the date and time when the row was soft deleted.
        /// The value of the DeletedOn is set when the row is soft deleted
        /// and unset when the row is restored.
        /// The DeletedOn column is only visible in the internal table
        /// but not in the user view of that table.
        /// </remarks>
        /// <example>
        ///   The following example shows that the DeletedOn value is auto-generated and cannot be changed manually.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll(); 
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             table.GrantAll();
        ///             
        ///             //Inserting a new row
        ///             var rowId = table.InsertRow();
        /// 
        ///             //Reading the value of the DeletedOn column
        ///             Console.WriteLine("Before deletion: deleted on = {0}",
        ///                 table.SystemColumns.DeletedOn.Read(rowId, DataSource.InternalTable).GetDateTime());
        /// 
        ///             //Trying to modify the DeletedOn value
        ///             table.SystemColumns.DeletedOn.Update(rowId, DataSource.InternalTable, DateTime.Now);
        /// 
        ///             //Reading the value of the DeletedOn column
        ///             Console.WriteLine("After trying to update: deleted on = {0}",
        ///                 table.SystemColumns.DeletedOn.Read(rowId, DataSource.InternalTable).GetDateTime());
        /// 
        ///             //Soft deleting the row
        ///             table.DeleteRow(rowId);
        /// 
        ///             //Reading the value of the DeletedOn column
        ///             Console.WriteLine("After soft deleting: deleted on = {0}",
        ///                 table.SystemColumns.DeletedOn.Read(rowId, DataSource.InternalTable).GetDateTime());
        /// 
        ///             //Restoring the row
        ///             table.RestoreRow(rowId);
        /// 
        ///             //Reading the value of the DeletedOn column
        ///             Console.WriteLine("After restoring: deleted on = {0}",
        ///                 table.SystemColumns.DeletedOn.Read(rowId, DataSource.InternalTable).GetDateTime());
        ///         }
        ///     }
        /// </code>
        /// </example>
        public DateTimeColumn DeletedOn
        {
            get
            {
                return _deletedOnColumn ??
                       (_deletedOnColumn =
                        _table.Columns.Single(c => c.Name == Db.Tables.UserTable.Col.DeletedOn) as DateTimeColumn);
            }
        }

        /// <summary>
        ///   Gets the row IsActive system column.
        /// </summary>
        /// <remarks>
        /// <para>The value of this column determines whether a row is soft deleted or not.
        /// If the value is 1 then the row is active and is visible both in
        /// the internal table and in the user view of that table.
        /// If the value is 0 then the row is soft deleted and is only visible
        /// in the internal table.
        /// </para>
        /// <para>
        /// Deleting one row may trigger deleting other rows if they have a reference on the row to be deleted
        /// and that reference has the CascadeDelete property set to true. If one reference in such a chain
        /// has the CascadeDelete property set to false then the whole transaction is cancelled
        /// and an exception is thrown. 
        /// </para>
        /// </remarks>
        /// <example>
        ///   The following example shows how to soft delete a row be setting its IsActive column value.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll(); 
        ///             
        ///             //Adding two tables
        ///             var firstTable = domain.AddTable("first_table");
        ///             var secondTable = domain.AddTable("second_table");
        /// 
        ///             firstTable.GrantAll();
        ///             secondTable.GrantAll();
        /// 
        ///             //Adding a reference
        ///             var refColumn = firstTable.AddColumn("ref", ColumnType.Reference)
        ///                 as RefColumn;
        /// 
        ///             refColumn.AddTarget(secondTable).HasCascadeDelete = true;
        /// 
        ///             //Inserting two rows
        ///             var id = secondTable.InsertRow();
        ///             firstTable.InsertRow(refColumn.Value(id));
        /// 
        ///             Console.WriteLine("The first table: row count = {0}", firstTable.RowCount);
        ///             Console.WriteLine("The second table: row count = {0}", secondTable.RowCount);
        /// 
        ///             //Soft deleting the row in the second table by setting its IsActive column value
        ///             secondTable.SystemColumns.IsActive.Update(id, DataSource.InternalTable, 0);
        /// 
        ///             Console.WriteLine("Soft deleting the row in the second table");
        /// 
        ///             Console.WriteLine("The first table: row count = {0}", firstTable.RowCount);
        ///             Console.WriteLine("The second table: row count = {0}", secondTable.RowCount);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public BoolColumn IsActive
        {
            get
            {
                return _isActiveColumn ??
                       (_isActiveColumn =
                        _table.Columns.Single(c => c.Name == Db.Tables.UserTable.Col.IsActive) as BoolColumn);
            }
        }

        /// <summary>
        ///   Gets the row RowVersion system column.
        /// </summary>
        /// <remarks>
        ///   This column contains a random guid value that is auto-regenerated
        /// after each row insert or update. That value can be used
        /// for an optimistic concurrency control.
        /// </remarks>
        /// <example>
        ///   The following example shows that the RowVersion value is auto-regenerated.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll();
        /// 
        ///             //Creating a table
        ///             var table = domain.AddTable("my_table");
        ///             table.GrantAll();
        ///             
        ///             //Inserting a row
        ///             var id = table.InsertRow();
        /// 
        ///             Console.WriteLine("Inserting the row: row version = {0}",
        ///                 table.SystemColumns.RowVersion.Read(id).GetGuid());
        /// 
        ///             //Updating a row
        ///             table.SystemColumns.Owner.Update(id, "new_owner");
        /// 
        ///             Console.WriteLine("Updating the row: row version = {0}",
        ///                 table.SystemColumns.RowVersion.Read(id).GetGuid());
        ///         }
        ///     }
        /// </code>
        /// </example>
        public GuidColumn RowVersion
        {
            get
            {
                return _rowVersionColumn ??
                       (_rowVersionColumn =
                        _table.Columns.Single(c => c.Name == Db.Tables.UserTable.Col.RowVersion) as GuidColumn);
            }
        }
    }
}